
#include <project_config.h>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <map>
#include <vector>
#include <chrono>
#include <any>

using namespace std;



class RunCodeToken {

public:
    string token_type = "";
    vector<string> source_code;
    void* runtime_pointer;
    string code = "";
};

class JsRuntime {

public:
    string runtime_name = "";
    map<string, any> values;
    map<string , JsRuntime> functions;
    vector<string> codes;
    vector<RunCodeToken> RunCodeTokens;
    string path = "";

    std::string trim_str(const std::string& str) {
        size_t first = str.find_first_not_of(" \t\r\n");
        size_t last = str.find_last_not_of(" \t\r\n");

        if (first != std::string::npos && last != std::string::npos) {
            return str.substr(first, last - first + 1);
        }

        return "";
    }

    bool startsWith_str(const std::string& str, const std::string& prefix) {
        if (prefix.length() > str.length()) {
            return false;
        }
        return std::equal(prefix.begin(), prefix.end(), str.begin());
    }

    JsRuntime(const string& name , const vector<string>& codes) {
        this -> runtime_name = name;
        this -> codes = codes;
    }

    void build() {
        for (int i = 0 ; i < codes.size() ; i++) {
            string code = trim_str(codes[i]);
            vector<string> strcutrues;
            
            if (code.empty()) continue;
            if (startsWith_str(code, "//")) {
                continue;
            }
            if (startsWith_str(code, "var")) {
                string value_name = trim_str(code.substr(3 ,code.find("=")-3));
                string values = code.substr(code.find("=")+1);
                values = trim_str(values);
                strcutrues.push_back("var");
                strcutrues.push_back(value_name);
                strcutrues.push_back(values);
                //cout << value_name << endl; 
            }
            else if (startsWith_str(code, "const")) {
                string value_name = trim_str(code.substr(3 ,code.find("=")-3));
                string values = code.substr(code.find("=")+1);
                values = trim_str(values);
                strcutrues.push_back("const");
                strcutrues.push_back(value_name);
                strcutrues.push_back(values);
                //cout << value_name << endl; 
            }
            else {
                strcutrues.push_back(code);
            }
            JsRuntime* ptr = this;
            auto* tokens = new RunCodeToken();
            tokens ->token_type = strcutrues[0];
            tokens -> source_code = strcutrues;
            tokens -> runtime_pointer = ptr;
            tokens -> code = code;

            RunCodeTokens.push_back(*tokens);
        }
    }

    any getExpression(string expression) {
        if (expression.empty()) {
            return "";
        }
        // 进行表达式分割，和Js一样的语法.
        // 保留分隔符的，例如 10 + 10 - 100 * (123 - 20) 分割成 10 ,+ ,10 ,- ,100, *, ( 123 - 20 )
        vector<string> strcutrues;
        string token;
        bool is_in_1 = false; // "
        bool is_in_2 = false; // '
        bool is_in_3 = false; // `
        bool is_in_4 = false; // ( or )
        bool is_in_5 = false; // [ or ]
        bool is_in_6 = false; // { or }

        for (int i = 0 ; i < expression.size() ; i++) {
            char c = expression[i];
            if (c == '`' && !is_in_3) {
                is_in_3 = true;
                token += c;
                continue;
            }
            if (c == '`' && is_in_3) {
                is_in_3 = false;
                token += c;
                continue;
            }
            if (c == '"' && !is_in_1) {
                is_in_1 = true;
                token += c;
                continue;
            }
            if (c == '"' && is_in_1) {
                is_in_1 = false;
                token += c;
                continue;
            }
            if (c == '\'' && !is_in_2) {
                is_in_2 = true;
                token += c;
                continue;
            }
            if (c == '\'' && is_in_2) {
                is_in_2 = false;
                token += c;
                continue;
            }
            if (c == '(' && !is_in_4) {
                is_in_4 = true;
                continue;
            }
            if (c == '(' && is_in_4) {
                is_in_4 = false;
                continue;
            }
            if (c == ')' && !is_in_4) {
                is_in_4 = true;
        }
    }
    
    void run() {
        for (int i = 0 ; i < RunCodeTokens.size() ; i++) {
            RunCodeToken token = RunCodeTokens[i];
            if (token.token_type == "var") {
                string value_name = token.source_code[1];
                string value = token.source_code[2];
                this->values[value_name] = getExpression(value);
                continue;
            }
            else if (token.token_type == "const") {
                string value_name = token.source_code[1];
                string value = token.source_code[2];
                // 检查是否已经定义过
                if (this->values.find(value_name) != this->values.end()) {
                    string error_message = "error: " + token.code + " already defined";
                    throw runtime_error(error_message.c_str());
                }
                this->values[value_name] = getExpression(value);
                continue;
            }
        }
    }
};



map<long , JsRuntime> runtimes_vm;